package com.gopay.checkorder.service.task;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BisBankOrderQueryDAO;
import com.gopay.checkorder.service.BankOrderService;
import com.gopay.checkorder.service.alarm.OrderAlarmDataCollector;
import com.gopay.checkorder.service.alarm.OrderAlarmRecordStorage;
import com.gopay.checkorder.service.task.thread.CheckOrderTaskThread;
import com.gopay.checkorder.service.task.thread.CheckOrderThread;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.bank.BankOrderType;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.util.DateUtils;

public class corpB2BCheckOrderJob  extends Observable implements Task {
    private final static Logger logger = LoggerFactory.getLogger("CHECK_ORDER");

    private final static int MAX_SIZE = 10000;
    
    @Resource(name = "bisBankOrderQueryDAO")
    private BisBankOrderQueryDAO bisBankOrderQueryDAO;

    @Resource(name = "checkOrderTaskThread")
    private CheckOrderTaskThread checkOrderTaskThread;
    
    private final static int THREAD_SIZE = 10;
    private ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_SIZE);
    
    @Resource(name = "orderAlarmRecordStorage")
	private OrderAlarmRecordStorage orderAlarmRecordStorage;
    
    @Resource(name = "bankOrderService")
    private BankOrderService bankOrderService;
    
    private void printLog(StopWatch sw,String prefix){
        sw.split();
        logger.error(prefix+"------,耗时="+sw.getSplitTime());
    }
    
    @Override
    public void doTask() {
      
        try{
            StopWatch sw=new StopWatch();
            sw.start();
            printLog(sw,"corpB2BCheckOrderJob------start");
            
            int pageSize = 100;
            int count = 0;
    
           
            Date date = new Date();
            int resCount = getCheckOrderCount(date);
            printLog(sw,"corpB2BCheckOrderJob------对单总数量="+resCount);
            // 订单对账报警采集者
			OrderAlarmDataCollector alarmCollector = new OrderAlarmDataCollector();
            List<BankOrder> list = null;
            while (count < resCount) {
                list = getCheckOrder(date, 1, pageSize);
                if (list == null || list.size() == 0) {
                    printLog(sw,"corpB2BCheckOrderJob------分页为空，跳出while循环");
                    break;
                }
                printLog(sw,"corpB2BCheckOrderJob------list.size()="+list.size()+",count="+count);
               
                //
                //订单队列              
                ConcurrentLinkedQueue<BankOrder> queue=new ConcurrentLinkedQueue<BankOrder>();
                queue.addAll(list);
    
                //同步锁存器
                CountDownLatch latch = new CountDownLatch(queue.size());
                
                //线程池中线程全部参与
                for(int i=0;i<THREAD_SIZE;i++){
                    CheckOrderThread thread=new CheckOrderThread(bankOrderService,queue,latch,alarmCollector);
                    threadPool.execute(thread);
                    
                }
                
                // 同步锁存器等待所有线程执行完成
                if(!latch.await(118, TimeUnit.SECONDS)){
                    logger.error("同步锁存器等待超时了 latch.count=" + latch.getCount());
                    threadPool.awaitTermination(1, TimeUnit.SECONDS);
                }
                
                count += pageSize;
            }
            
            // 判断报警阈值并保存报警记录
     	    orderAlarmRecordStorage.store(alarmCollector);
            
            printLog(sw,"corpB2BCheckOrderJob------结束while循环,resCount="+resCount);
           
            printLog(sw,"corpB2BCheckOrderJob------end");
            sw.stop();
            
        }catch (Throwable t) {
            logger.error("执行对单Task时出现异常" ,t);
        }      
    }
    
    /**
     * 待对账订单笔数
     * @param orderStatus
     * @param totalCheckTimes
     * @return
     */
    protected int getCheckOrderCount(Date date){
        Map<String, Object> params = new HashMap<String, Object>();
        StringBuffer hql = new StringBuffer("select count(*) ");
        hql.append(buildHqlAndParamsOfCorpB2B(params));
       
        int resCount = bisBankOrderQueryDAO.findCountByHql(hql.toString(), params);
        if (resCount > MAX_SIZE) {
            resCount = MAX_SIZE;
        }
        return resCount;
    }
    
    /**
     * 分页查询对账记录
     * @param orderStatus
     * @param totalCheckTimes
     * @param pageIndex
     * @param pageSize
     * @return
     */
    protected List<BankOrder> getCheckOrder(Date date, int pageIndex, int pageSize){
        Map<String, Object> params = new HashMap<String, Object>();
        
        StringBuilder sb=new StringBuilder();
        sb.append(buildHqlAndParamsOfCorpB2B(params));
        sb.append(" order by totalCheckTimes asc ");

        return bisBankOrderQueryDAO.findByHql(sb.toString(), params, pageIndex, pageSize);
    }
   
    
    private String buildHqlAndParamsOfCorpB2B(Map<String, Object> params){
        StringBuffer hql = new StringBuffer("");
        hql.append(" from BankOrder ");
        hql.append(" where orderStatus in (:orderStatus00,:orderStatus92)  ");
        hql.append(" and bankBizProdCode = :bankBizProdCode  ");
        hql.append(" and orderType = :orderType ");   
        hql.append(" and totalCheckTimes >= 7 ");   
        hql.append(" and bankCode != :bankCode ");   
       // hql.append(" and bankCode not in (:bankCodeIcbc,:bankCodeCmb,:bankCodeCcb,:bankCodeAbc,:bankCodeBoc) ");   
        hql.append(" and sendBankTm >to_date(:beginTime,'yyyyMMddHH24miss') ");
        
        //map        
        params.put("orderStatus00", BankOrderStatus.PROCESS);
        params.put("orderStatus92", BankOrderStatus.VERIFY_FAIL);
       // params.put("orderStatus96", BankOrderStatus.ENTER_ACCOUNT_FIAL);
        params.put("bankBizProdCode", BisBankBusinessProd._01.value);
        params.put("orderType", BankOrderType.GOPAY_BIS_ORDER);
        //add by lilili 去掉招行，招行单独对账处理
        params.put("bankCode", BankConstants.BANK_LOGO_CMB);
       /* params.put("bankCodeIcbc", BankConstants.BANK_LOGO_ICBC);
        params.put("bankCodeCmb", BankConstants.BANK_LOGO_CMB);
        params.put("bankCodeCcb", BankConstants.BANK_LOGO_CCB);
        params.put("bankCodeAbc", BankConstants.BANK_LOGO_ABC);
        params.put("bankCodeBoc", BankConstants.BANK_LOGO_BOC);*/
        
        //开始时间--最近20天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -20);
        params.put("beginTime",DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss"));
        
        return hql.toString();
    }

}
